from manimlib import *


class Scene01(Scene):
    def construct(self):
        axes = Axes(
            x_range=[-5, 5, 1],
            y_range=[-3, 3, 1],
            width=10, height=6,
            axis_config={"include_tip": False}
        )
        self.add(axes)
        fun1 = axes.get_graph(lambda x: np.sin(PI * x / 2), color=BLUE)
        fun2 = axes.get_graph(lambda x: -np.sin(PI * x / 2), color=GREEN)
        self.add(fun1, fun2)
        fun1.add_updater(lambda a: a.become(
            axes.get_graph(lambda x: np.sin(PI * x / 2 + self.time), color=BLUE)
        ))
        fun2.add_updater(lambda a: a.become(
            axes.get_graph(lambda x: -np.sin(PI * x / 2 - self.time), color=GREEN)
        ))
        self.add(fun1, fun2)
        fun3 = axes.get_graph(lambda x: 0, color=RED)
        fun3.add_updater(lambda a: a.become(
            axes.get_graph(lambda x: np.sin(PI * x / 2 + self.time) - np.sin(PI * x / 2 - self.time), color=RED)
        ))
        self.add(fun3)
        self.wait(2 * PI)


class Scene02(Scene):
    def construct(self):
        numlines = VGroup(*[NumberLine(x_range=[-4, 4, 1]).set_color(GREY) for i in range(3)]).arrange(DOWN, buff=1.5)
        self.add(numlines)
        fun1 = ParametricCurve(lambda t: np.array([t, 0.5 * np.sin(PI / 8 * t), 0]), t_range=[0, 8], color=RED).move_to(
            UP * 1.95)
        fun1_1 = DashedVMobject(fun1.copy().rotate(PI, about_point=fun1.get_bottom()))
        self.add(fun1, fun1_1)
        fun2 = ParametricCurve(lambda t: np.array([t, 0.5 * np.sin(PI / 4 * t), 0]), t_range=[0, 8], color=RED).move_to(
            numlines[1].get_center())
        fun2_1 = DashedVMobject(fun2.copy().flip(axis=RIGHT))
        self.add(fun2, fun2_1)
        fun3 = ParametricCurve(lambda t: np.array([t, 0.5 * np.sin(PI / (8 / 3) * t), 0]), t_range=[0, 8],
                               color=RED).move_to(numlines[2].get_center())
        fun3_1 = DashedVMobject(fun3.copy().flip(axis=RIGHT))
        self.add(fun3, fun3_1)

        text = VGroup(
            Tex(r"l={\lambda\over 2}"),
            Tex(r"l={2\lambda\over 2}"),
            Tex(r"l={3\lambda\over 2}")
        ).set_color(BLACK)
        for i in range(3):
            text[i].next_to(numlines[i], RIGHT)

        self.add(text)


class Scene03(Scene):
    def construct(self):
        numlines = VGroup(*[NumberLine(x_range=[-4, 4, 1]).set_color(GREY) for i in range(3)]).arrange(DOWN, buff=1.5)
        self.add(numlines)
        fun1 = ParametricCurve(lambda t: np.array([t, 0.5 * np.sin(PI / 16 * t), 0]), t_range=[0, 8],
                               color=RED)
        fun1_1 = DashedVMobject(fun1.copy().flip(axis=RIGHT))
        VGroup(fun1, fun1_1).arrange(DOWN, buff=0).move_to(numlines[0].n2p(0))
        self.add(fun1, fun1_1)
        fun2 = ParametricCurve(lambda t: np.array([t, 0.5 * np.sin(PI / (16 / 3) * t), 0]), t_range=[0, 8],
                               color=RED).move_to(
            numlines[1].get_center())
        fun2_1 = DashedVMobject(fun2.copy().flip(axis=RIGHT))
        self.add(fun2, fun2_1)
        fun3 = ParametricCurve(lambda t: np.array([t, 0.5 * np.sin(PI / (16 / 5) * t), 0]), t_range=[0, 8],
                               color=RED).move_to(numlines[2].get_center())
        fun3_1 = DashedVMobject(fun3.copy().flip(axis=RIGHT))
        self.add(fun3, fun3_1)

        text = VGroup(
            Tex(r"l={\lambda_1\over 4}"),
            Tex(r"l={3\lambda_2\over 4}"),
            Tex(r"l={5\lambda_3\over 4}")
        ).set_color(BLACK)
        for i in range(3):
            text[i].next_to(numlines[i], RIGHT)

        self.add(text)


class TestSurface(Scene):
    def construct(self):
        dot = Dot()
        self.add(dot)
        anim_kwargs = {
            'big_radius': 5,
            'n_circles': 8,
            'lag_ratio': 0.1,
            'color': YELLOW
        }
        self.play(Broadcast(dot, **anim_kwargs))
        self.wait()


class TestStreamLines(Scene):
    def construct(self):
        coord = Axes(x_range=[-7, 7, 1], width=14,
                     y_range=[-4, 4, 1], height=8)
        s = StreamLines(
            lambda x, y: (x * 0.7 + y * 0.5, y * 0.7 - x * 0.5),
            coord,
            magnitude_range=(0.5, 5)
        )
        asl = AnimatedStreamLines(s)
        self.add(coord, asl)
        self.wait(5)


class TestDotCloud(Scene):
    def construct(self):
        # frame = self.camera.frame
        # frame.set_euler_angles(
        #     theta=-30 * DEGREES,
        #     phi=70 * DEGREES,
        # )

        points = (np.random.random(300) - 0.5) * 8
        points.resize(100, 3)

        dc = DotCloud(
            points
        )
        dc.to_grid(5, 5, 5)
        dc.make_3d()
        self.add(dc)
        self.play(dc.animate.scale(0.5, scale_radii=False))
